//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <ddk.h>
#include "gdivga.h"
#include "osenv.h"
#include "os.h"
#include "gdimisc.h"
#include <fb.h>
#include <buf_io.h>
#include <display.h>
#include "DisplayMode.h"
#include "vgadrv.h"

#ifdef _DEBUG
#define Assert(x)   if (!((bool)(x))) { \
                        __asm__ __volatile__("int $3"); \
                    }
#else
#define Assert(x)
#endif

extern void Video_WriteDAC(int index, int r, int g, int b);
extern void  Screen_Init(DisplayModePtr mode);

bufio_t    *g_pFrameBuf = NULL;

// The gdivideo driver's classfactory
//
EXTERN IDeviceDriver * CDECL CreateGDIVGA(uint_t uDeviceNo, void *pvParameter)
{
    GDIVideo *pVGADriver = new GDIVideo;
    if (NULL == pVGADriver) {
        Assert(0 && "There is not enough memeory!");
        return NULL;
    }

    pVGADriver->AddRef();

    return pVGADriver;
}

ECode GDIVideo::Read(
    /* [in] */ Int64 u64Offset,
    /* [in] */ Int32 bytesToRead,
    /* [out] */ MemoryBuf * pBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode GDIVideo::Write(
    /* [in] */ Int64 u64Offset,
    /* [in] */ const MemoryBuf & buffer,
    /* [out] */ Int32 * pBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return NOERROR;
}

ECode GDIVideo::Control(
    /* [in] */ Handle32 nControlCode,
    /* [in] */ const MemoryBuf & inBuffer,
    /* [out] */ MemoryBuf * pOutBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    if ((nControlCode < 0) || (nControlCode > 7)
        || (ppCompletionEvent && *ppCompletionEvent)) {
        return E_INVALID_ARGUMENT;
    }

    //Init video
    if (3 == nControlCode) {
        void       *pMappedAddr = NULL;

        zee_video_init_mode((char *)inBuffer.GetPayload());
        g_pFrameBuf = \
            zee_video_init_framebuffer((DisplayModePtr)inBuffer.GetPayload());

        g_pFrameBuf->map(g_pFrameBuf->addr, g_pFrameBuf->size,
                    (void **)&pMappedAddr, 0, g_pFrameBuf->video_mem);

        if (pOutBuffer == NULL) {
            return E_INVALID_ARGUMENT;
        }
        *(uint32_t *)pOutBuffer->GetPayload() = (uint32_t)pMappedAddr;
        pOutBuffer->SetUsed(sizeof(uint32_t));

        goto SUCCESS;
    }

    //zee_video_cleanup();
    if (6 == nControlCode) {
        zee_video_cleanup();
        if (g_pFrameBuf != NULL) {
            xfree(g_pFrameBuf);
        }
        goto SUCCESS;
    }

    if (7 == nControlCode) {
        FrameBufferFormat fbFormat;
        if (pOutBuffer == NULL) {
            return E_INVALID_ARGUMENT;
        }
        if (pOutBuffer->GetCapacity() < (int)sizeof(FrameBufferFormat)) {
            return E_OUT_OF_MEMORY;
        }
        fbFormat.Color = COLOR_RGB565;
        fbFormat.Bpp = 16;
        fbFormat.Width = 800;
        fbFormat.Height = 600;
        pOutBuffer->Copy((Byte *)&fbFormat, sizeof(FrameBufferFormat));

        pOutBuffer->SetUsed(sizeof(FrameBufferFormat));
    }

SUCCESS:
    return NOERROR;
}
